package com.ma.chapter4.t4;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.List;

/*
 同步模式之保护性暂停  信号抢模式
       即 Guarded Suspension，用在一个线程等待另一个线程的执行结果
 要点
     1、有一个结果需要从一个线程传递到另一个线程，让他们关联同一个 GuardedObject
     2、如果有结果不断从一个线程到另一个线程那么可以使用消息队列（见生产者/消费者）
     3、JDK 中，join 的实现、Future 的实现，采用的就是此模式
     4、因为要等待另一方的结果，因此归类到同步模式
 */
@Slf4j(topic = "m.test")
public class GuardedObjectTest {
    //线程1等待线程2的下载结果
    public static void main(String[] args) {
        GuardedObject guardedObject = new GuardedObject();

        new Thread(() -> {
            //等待结果
            log.debug("等待结果");
            List<String> list = (List<String>) guardedObject.get();
            log.debug("结果是大小：{}", list.size());
        }, "t1").start();

        new Thread(() -> {
            log.debug("执行下载");
            try {
                List<String> download = Downloader.download();
                guardedObject.complete(download);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, "t2").start();

    }


}

class GuardedObject {
    //结果
    private Object response;

    //获取结果
    public Object get(long timeout) {
        synchronized (this) {
            long begin = System.currentTimeMillis();
            long passedTime = 0;
            //没有结果
            while (response == null) {
                //这一轮循环应该等待的时间
                long waitTime = timeout - passedTime;
                if (waitTime <= 0) {
                    break;
                }
                try {
                    this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //经历的时间
                passedTime = System.currentTimeMillis() - begin;
            }
            return response;
        }
    }

    //获取结果
    public Object get() {
        synchronized (this) {
            //没有结果
            while (response == null) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return response;
        }
    }

    //产生结果
    public void complete(Object response) {
        synchronized (this) {
            //给结果变量赋值
            this.response = response;
            this.notifyAll();
        }
    }

}
